﻿
Imports System.Threading
Imports std
Imports lock_t = lock(Of locks.monitorlock)

Partial Public Class callbackManager
    Private Shared ReadOnly CALLBACKMANAGER_CHECK_QUEUE_LENGTH As Int64
    Private Shared ReadOnly CALLBACKMANAGER_CHECK_QUEUE_TICKS As Int64
    Private Shared ReadOnly CALLBACKMANAGER_CHECK_QUEUE_INTERVAL_TICKS As Int64
    Private Shared ReadOnly CALLBACKMANAGER_CHECK_QUEUE_UNCHANGED_CYCLE As Int64
    Private ReadOnly q As list(Of callbackAction) = Nothing
    Private ReadOnly are As AutoResetEvent = Nothing
    Private ReadOnly checkThread As Thread = Nothing
    Private lock As lock_t

    Private Sub trigger_check() Implements icallbackManager.trigger_check
        are.Set()
    End Sub

    Private Sub action_check_lock(ByVal action As callbackAction,
                                  Optional ByVal pendingOper As void = Nothing,
                                  Optional ByVal endingOper As void = Nothing)
        assert(Not action Is Nothing)
        assert(action.pending())
        action.action_check()
        If action.pending() Then
            If Not pendingOper Is Nothing Then
                lock.wait()
                pendingOper()
                lock.release()
            End If
        Else
            assert(action.ending())
            If Not endingOper Is Nothing Then
                lock.wait()
                endingOper()
                lock.release()
            End If
            assert_begin(action)
        End If
    End Sub

    Private Sub check_queue()
        Dim unchangedCycle As Int64 = 0
        Dim tp As ithreadpool = Nothing
        tp = resolve(Of ithreadpool)()
        While True
            counter.recordTimeBegin()
            Dim changed As Int64 = 0
            counter.increase(CALLBACKMANAGER_CHECK_QUEUE_LENGTH, q.size())
            Dim it As list(Of callbackAction).iterator = Nothing
            it = q.begin()
            While it <> q.end() AndAlso Not tp.stopping()
                Dim c As callbackAction = Nothing
                c = (+it)
                If debugassert(Not c Is Nothing) AndAlso debugassert(c.pending()) Then
                    action_check_lock(c,
                                      endingOper:=Sub()
                                                      changed += 1
                                                      it = q.erase(it)
                                                  End Sub)
                    If c.pending() Then
                        it += 1
                    End If
                Else
                    Exit While
                End If
            End While
            counter.recordTimeTicks(CALLBACKMANAGER_CHECK_QUEUE_TICKS)
            If changed > 0 Then
                counter.increase(CALLBACKMANAGER_CHECK_QUEUE_UNCHANGED_CYCLE, unchangedCycle)
                unchangedCycle = 0
            Else
                unchangedCycle += 1
            End If
            If tp.stopping() Then
                Exit While
            End If
            counter.recordTimeBegin()
            yield_wait(are)
            counter.recordTimeTicks(CALLBACKMANAGER_CHECK_QUEUE_INTERVAL_TICKS)
        End While
    End Sub

    Private Sub begin_check(ByVal action As callbackAction)
        assert(Not action Is Nothing)
        assert(action.pending())
        action_check_lock(action,
                          pendingOper:=Sub()
                                           q.push_back(action)
                                       End Sub)
    End Sub

    Public Function check_queue_length() As Int64
        Return q.size()
    End Function
End Class
